package com.wzc.basic.interceptor;


import com.wzc.basic.annotation.PreAuthorize;
import com.wzc.basic.jwt.JwtUtils;
import com.wzc.basic.jwt.Payload;
import com.wzc.basic.jwt.RsaUtils;
import com.wzc.org.mapper.EmployeeMapper;
import com.wzc.user.domain.Logininfo;
import com.wzc.user.util.LoginData;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.security.PublicKey;
import java.util.List;


@Component // 将当前类交给spring管理
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private EmployeeMapper employeeMapper;



    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求头中的token
        // 判断token是否为空
        // token不为空，判断logininfo是否为空（过期或没登录），提示用户重新登录
        // logininfo不为空，证明有登录，则刷新过期时间，并放行

        String jwtToken = request.getHeader("token"); // 获取请求头中的token
        if(jwtToken != null){ // 请求头中有token
//            Object logininfo = redisTemplate.opsForValue().get(token); // key 获取 logininfo
            // 解密
            PublicKey publicKey = RsaUtils.getPublicKey(JwtUtils.class.getClassLoader().getResource("auth_rsa.pub").getFile());
            try {
                //4.将jwtToken解析成想要的数据：LoginData
                Payload<LoginData> payload = JwtUtils.getInfoFromToken(jwtToken, publicKey, LoginData.class);

                if (payload != null) {//登录成功，而且没有过期
                    // 5. 获取登录信息对象
                    Logininfo logininfo = payload.getLoginData().getLogininfo();
                    // 6. 如果是用户 - 放行
                    if (logininfo.getType() == 1) {
                        return true;
                    }
                    // 7. 如果是后端管理员 - 验证权限【后端管理员 - 角色不一样 - 权限不一样】
                    // 8. 获取当前接口上注解里的sn - handler - 获取注解@PreAuthorize - 获取注解里面的sn
                    HandlerMethod handlerMethod = (HandlerMethod) handler; // 就是接收请求的接口 - 方法
                    // System.out.println(handlerMethod.getMethod().getName());  // 获取接口名
                    PreAuthorize annotation = handlerMethod.getMethodAnnotation(PreAuthorize.class);
                    if (annotation == null) { // 如果当前接口方法上没有这个注解 - 不需要校验权限 - 直接放行
                        return true;
                    } else {
                        String sn = annotation.sn();
                        // 9. 根据logininfo_id获取当前登录人的所有权限 - sn
                        List<String> sns = employeeMapper.loadPermissionsByLogininfoId(logininfo.getId());
                        if (sns.contains(sn)) {//有权限
                            return true;
                        } else { // else 会经过后置拦截器，可以在axios后置拦截器中判断弹出错误框
                            response.setContentType("application/json;charset=UTF-8");
                            response.getWriter().println("{\"success\":false,\"msg\":\"noPermission\"}");
                            return false;
                        }
                    }
                }
            } catch(ExpiredJwtException e){
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().println("{\"success\":false,\"msg\":\"timeout\"}");
                return false;
            }
        }
        /**
         * token为空或者logininfo为空
         * 我们需要返回一个信息给用户（没有登录）
         * 没有信息，手动拼写一个json格式的信息返回给前端 ：{"success":false,"msg":"noLogin"}
         *
         */
        response.setContentType("application/json;charset=utf-8"); // 设置格式，字符集
        PrintWriter writer = response.getWriter(); //
        // 后置拦截器接收，判断是否登录。
        writer.write("{\"success\":false,\"msg\":\"noLogin\"}");
        return false;
    }
}
